import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.AffineTransform;
import java.io.File;
import java.io.IOException;
import java.net.*;

/**
 * The main <code>JFrame</code> for the application.
 */
public class View extends JFrame implements ActionListener, MouseWheelListener {
	
	private boolean gameInProgress = false;	// whether or not there is a current game
	
	private TablePanel panel;
	private PlayerModel pm;
	private Model parent;
	
	private JMenuBar menuBar;
	private JMenu fileMenu, viewMenu, snapSubMenu, tableMenu, colourSubMenu, zoomSubMenu, serverMenu, helpMenu;
	public JMenu cardMenu;
	private JMenuItem fNewGameMenuItem, fQuitMenuItem;
	private JMenuItem cFlipMenuItem, cShuffleMenuItem, cBackMenuItem;
	private JMenuItem tAddDeckMenuItem;
	private JMenuItem sConnectMenuItem;
	private JMenuItem helpMenuItem;
// 	private JMenuItem aboutMenuItem;
	private JRadioButtonMenuItem tcGreenTableRadio, tcRedTableRadio, tcBlueTableRadio, tcPurpleTableRadio;
	private JRadioButtonMenuItem tsEnableCardSnapRadio, tsDisableCardSnapRadio;
	private JRadioButtonMenuItem vzEnableZoomRadio, vzDisableZoomRadio;
	
	private JScrollPane jsp;
	
	AffineTransform at;
	
	/**
	 * <ul><li>Constructs the <code>JFrame</code>.</li>
	 * <li>Connects to the {@link Model}.</li>
	 * <li>Creates the menu.</li></ul>
	 * 
	 * @param parent The <code>Model</code> to connect to.
	 */
	public View(Model parent) {
		
		super("Super Awesome Cards Win");
		
		menuBar = new JMenuBar();
		fileMenu = new JMenu("File");
		fileMenu.setMnemonic(KeyEvent.VK_F);
		menuBar.add(fileMenu);
			fNewGameMenuItem = new JMenuItem("New Game", KeyEvent.VK_N);
				KeyStroke ctrlNKeyStroke = KeyStroke.getKeyStroke("control N");
				fNewGameMenuItem.setAccelerator(ctrlNKeyStroke);
				fileMenu.add(fNewGameMenuItem);
				fNewGameMenuItem.addActionListener(this);
			fQuitMenuItem = new JMenuItem("Quit", KeyEvent.VK_Q);
				KeyStroke ctrlQKeyStroke = KeyStroke.getKeyStroke("control Q");
				fQuitMenuItem.setAccelerator(ctrlQKeyStroke);
				fileMenu.add(fQuitMenuItem);
				fQuitMenuItem.addActionListener(this);
		
		viewMenu = new JMenu("View");
		viewMenu.setMnemonic(KeyEvent.VK_V);
		menuBar.add(viewMenu);
			zoomSubMenu = new JMenu("Zoom");
			viewMenu.add(zoomSubMenu);
				ButtonGroup zoom = new ButtonGroup();
				vzEnableZoomRadio = new JRadioButtonMenuItem("Enable");
				vzDisableZoomRadio = new JRadioButtonMenuItem("Disable");
				zoomSubMenu.add(vzEnableZoomRadio);
				zoomSubMenu.add(vzDisableZoomRadio);
				zoom.add(vzEnableZoomRadio);
				zoom.add(vzDisableZoomRadio);
				vzEnableZoomRadio.setSelected(true);
				vzEnableZoomRadio.addActionListener(this);
				vzDisableZoomRadio.addActionListener(this);
		cardMenu = new JMenu("Card");
		cardMenu.setMnemonic(KeyEvent.VK_C);
		menuBar.add(cardMenu);
			cFlipMenuItem = new JMenuItem("Flip", KeyEvent.VK_F);
				KeyStroke fKeyStroke = KeyStroke.getKeyStroke("F");
				cFlipMenuItem.setAccelerator(fKeyStroke);
				cardMenu.add(cFlipMenuItem);
				cFlipMenuItem.addActionListener(this);
			cShuffleMenuItem = new JMenuItem("Shuffle", KeyEvent.VK_S);
				KeyStroke sKeyStroke = KeyStroke.getKeyStroke("S");
				cShuffleMenuItem.setAccelerator(sKeyStroke);
				cardMenu.add(cShuffleMenuItem);
				cShuffleMenuItem.addActionListener(this);
			cBackMenuItem = new JMenuItem("Send card to back", KeyEvent.VK_B);
				KeyStroke bKeyStroke = KeyStroke.getKeyStroke("B");
				cBackMenuItem.setAccelerator(bKeyStroke);
				cardMenu.add(cBackMenuItem);
				cBackMenuItem.addActionListener(this);
			
		tableMenu = new JMenu("Table");
		tableMenu.setMnemonic(KeyEvent.VK_T);
		menuBar.add(tableMenu);
			tAddDeckMenuItem = new JMenuItem("Add Deck...", KeyEvent.VK_A);
				tableMenu.add(tAddDeckMenuItem);
				tAddDeckMenuItem.addActionListener(this);
			snapSubMenu = new JMenu("Card Snap");
			tableMenu.add(snapSubMenu);
				ButtonGroup snap = new ButtonGroup();
				tsEnableCardSnapRadio = new JRadioButtonMenuItem("Enable");
				tsDisableCardSnapRadio = new JRadioButtonMenuItem("Disable");
				snapSubMenu.add(tsEnableCardSnapRadio);
				snapSubMenu.add(tsDisableCardSnapRadio);
				snap.add(tsEnableCardSnapRadio);
				snap.add(tsDisableCardSnapRadio);
				tsEnableCardSnapRadio.setSelected(true);
				tsEnableCardSnapRadio.addActionListener(this);
				tsDisableCardSnapRadio.addActionListener(this);
			colourSubMenu = new JMenu("Table Colour");
			tableMenu.add(colourSubMenu);
				ButtonGroup colour = new ButtonGroup();
				tcGreenTableRadio = new JRadioButtonMenuItem("Green");
				tcRedTableRadio = new JRadioButtonMenuItem("Red");
				tcBlueTableRadio = new JRadioButtonMenuItem("Blue");
				tcPurpleTableRadio = new JRadioButtonMenuItem("Purple");
				colourSubMenu.add(tcGreenTableRadio);
				colourSubMenu.add(tcRedTableRadio);
				colourSubMenu.add(tcBlueTableRadio);
				colourSubMenu.add(tcPurpleTableRadio);
				colour.add(tcGreenTableRadio);
				colour.add(tcRedTableRadio);
				colour.add(tcBlueTableRadio);
				colour.add(tcPurpleTableRadio);
				tcGreenTableRadio.setSelected(true);
				tcGreenTableRadio.addActionListener(this);
				tcRedTableRadio.addActionListener(this);
				tcBlueTableRadio.addActionListener(this);
				tcPurpleTableRadio.addActionListener(this);
				
		serverMenu = new JMenu("Server");
		serverMenu.setMnemonic(KeyEvent.VK_S);
		menuBar.add(serverMenu);
			sConnectMenuItem = new JMenuItem("Connect", KeyEvent.VK_C);
				serverMenu.add(sConnectMenuItem);
				sConnectMenuItem.addActionListener(this);
		
		helpMenu = new JMenu("Help");
		helpMenu.setMnemonic(KeyEvent.VK_H);
		menuBar.add(helpMenu);
			helpMenuItem = new JMenuItem("Get help online...", KeyEvent.VK_O);
				helpMenu.add(helpMenuItem);
				helpMenuItem.addActionListener(this);
		
		jsp = new JScrollPane();
		
		this.setJMenuBar(menuBar);
		this.setContentPane(jsp);
		setModel(parent);
		setPlayer(null);
		
		this.addWindowListener(new WL());
		this.setPreferredSize(new Dimension(800,600));
		this.pack();
		this.setVisible(true);		
		repaint();
	}
	
	/**
	 * Sets the {@link Model} that this frame is connected to.
	 * 
	 * @param m The model to set.
	 */
	public void setModel(Model m) {
		parent = m;
	}
	
	public void setPlayer(PlayerModel pm){
		this.pm = pm;
		if (pm==null) {
			Dbg.logln("View.setPlayer(null)");
			gameInProgress = false;
			JPanel currentpanel = new JPanel();
			jsp.setViewportView(currentpanel);
			//repaint();
		} else {
			Dbg.logln("View.setPlayer(PLAYER)");
			gameInProgress = true;
			panel = new TablePanel(pm, this);
			panel.addMouseWheelListener(this);
			jsp.setViewportView(panel);
			//repaint();
		}
	}
	
	/**
	 * The <code>WindowAdapter</code> that listens for <code>windowClosing</code> events.
	 */
	public class WL extends WindowAdapter {
		public void windowClosing(WindowEvent e) {
			System.exit(0);
		}
	}
	
	/**
	 * Processes mouse events for the menus.
	 */
	public void actionPerformed(ActionEvent ae) {
		
		if (gameInProgress) {
			Object source = ae.getSource();
			
			if(source == fQuitMenuItem) {
				//close
				System.exit(0);
				
			} else if(source == fNewGameMenuItem) {
				newGame();
			} else if(source == cFlipMenuItem) {
				pm.flipSelected();
			} else if(source == cShuffleMenuItem) {
				pm.shuffleSelected();
				panel.repaint();
			} else if(source == cBackMenuItem) {
				pm.sendToBack();
			} else if(source == tAddDeckMenuItem) {
				addDeck();
			} else if(source == tcGreenTableRadio) {
				System.out.println("Change table colour to - green");
				panel.changeBackgroundColour("green");
			} else if(source == tcRedTableRadio) {
				System.out.println("Change table colour to - red");
				panel.changeBackgroundColour("red");
			} else if(source == tcBlueTableRadio) {
				System.out.println("Change table colour to - blue");
				panel.changeBackgroundColour("blue");
			} else if(source == tcPurpleTableRadio) {
				System.out.println("Change table colour to - purple");
				panel.changeBackgroundColour("purple");
			} else if(source == sConnectMenuItem) {
				System.out.println("Server Connect");
				doConnectionDialog();
			} else if(source == tsEnableCardSnapRadio) {
				System.out.println("Snap Enabled");
				pm.setSnap(true);
			} else if(source == tsDisableCardSnapRadio) {
				System.out.println("Snap Disabled");
				pm.setSnap(false);
			} else if(source == vzEnableZoomRadio) {
				System.out.println("Zoom Enabled");
				panel.setZoom(true);
			} else if(source == vzDisableZoomRadio) {
				System.out.println("Zoom Disabled");
				panel.setZoom(false);
			} else if(source == helpMenuItem) {
				String helpurl = "http://code.google.com/p/ipcards/wiki/Help";
				try {
					SystemSpecific.launchWebBrowser(helpurl);
				} catch (Exception e) {
					e.printStackTrace();
					alert("There was a problem opening the web browser.  For help, visit "+helpurl);
				}
			}
		}
		
	}
	
	public void alert(String msg) {
		JOptionPane.showMessageDialog(null, msg);
	}

	public void mouseWheelMoved(MouseWheelEvent mw) {
		if (gameInProgress) {
			panel.zoom(mw.getWheelRotation());
			repaint();
		}
	}
	
	private void doConnectionDialog() {
		
		String host = JOptionPane.showInputDialog(null, "Enter Server host", "localhost");
		int port = Model.DEFAULT_PORT;
		
		if(host == null)
			return;
			
		String p = JOptionPane.showInputDialog(null, "Enter Server port", Model.DEFAULT_PORT);
		
		if(p == null)
			return;
			
		try {
			port = Integer.valueOf(p);
			parent.connectToRemoteServer(host, port);
			
		} catch(NumberFormatException nfe) {
			alert("Invalid Input - port must be numerical");
		} catch (UnknownHostException e) {
			alert("Unable to connect to host: " + host + " on port " + port);
		} catch (IOException e) {
			alert("Unable to connect to host: " + host + " on port " + port);
		}
	}
	
	private void newGame() {
		parent.getRoom().getTable().removeAllCards();
		panel.repaint();
	}
	
	private class DeckFileFilter extends javax.swing.filechooser.FileFilter {
		public boolean accept(File f) {
			if (f.isDirectory()) {
				return true;
			}
			return f.getName().endsWith(".deck");
		}
		public String getDescription() {
			return "*.deck";
		}
	}
	
	JFileChooser loadChooser = new JFileChooser("./decks");
	{loadChooser.addChoosableFileFilter(new DeckFileFilter());}
	private void addDeck(){
		int returnVal = loadChooser.showOpenDialog(this);
		if (returnVal==JFileChooser.APPROVE_OPTION) {
			File file = loadChooser.getSelectedFile();
			loadChooser.setCurrentDirectory(file);
			parent.getRoom().getTable().addDeck(new Deck(file));
		}
		panel.repaint();
	}
	
	public void repaint() {
		Dbg.logln("View.repaint");
		super.repaint();
	}
}
